package com.vladium.utils;

import java.util.Arrays;

// ----------------------------------------------------------------------------
/**
 * A non-shell profile tree node implementation. This implementation trades off
 * some object orientation "niceness" to achieve more memory compactness.
 * 
 * @author (C) <a
 *         href="http://www.javaworld.com/columns/jw-qna-index.shtml">Vlad
 *         Roubtsov</a>, 2003
 */
final class ObjectProfileNode extends AbstractProfileNode {
	// public: ................................................................
	public Object object() {
		return m_obj;
	}

	public String name() {
		return m_link == null ? ObjectProfiler.INPUT_OBJECT_NAME : m_link.name();
	}

	public IObjectProfileNode shell() {
		return m_shell;
	}

	public IObjectProfileNode[] children() {
		return m_children;
	}

	public int refcount() {
		return m_refcount;
	}

	public boolean traverse(final INodeFilter filter, final INodeVisitor visitor) {
		if ((visitor != null) && ((filter == null) || filter.accept(this))) {
			visitor.previsit(this);
			final IObjectProfileNode[] children = m_children;
			for (int i = 0; i < children.length; ++i) {
				children[i].traverse(filter, visitor);
			}
			visitor.postvisit(this);
			return true;
		}
		return false;
	}

	// protected: .............................................................
	// package: ...............................................................
	/*
	 * This method manages the vector in m_children field for an unfinished
	 * node.
	 */
	void addFieldRef(final IObjectProfileNode node) {
		// [m_size is the child count]
		IObjectProfileNode[] children = m_children;
		final int childrenLength = children.length;
		if (m_size >= childrenLength) {
			final IObjectProfileNode[] newchildren = new IObjectProfileNode[Math.max(1, childrenLength << 1)];
			System.arraycopy(children, 0, newchildren, 0, childrenLength);
			m_children = children = newchildren;
		}
		children[m_size++] = node;
	}

	/*
	 * This method is called once on every node to lock it down into its
	 * immutable and most compact representation during phase 2 of profile tree
	 * construction.
	 */
	void finish() {
		final int childCount = m_size; // m_size is the child count for a
		// non-shell node
		if (childCount > 0) {
			if (childCount < m_children.length) {
				final IObjectProfileNode[] newadj = new IObjectProfileNode[childCount];
				System.arraycopy(m_children, 0, newadj, 0, childCount);
				m_children = newadj;
			}
			// Arrays.sort( m_children );
			int size = 0;
			for (int i = 0; i < childCount; ++i) {
				size += m_children[i].size();
			}
			m_size = size; // m_size is the full node size for all nodes
		}
	}

	ObjectProfileNode(final ObjectProfileNode parent, final Object obj, final ILink link) {
		super(parent);
		m_obj = obj;
		m_link = link;
		m_refcount = 1;
		m_children = EMPTY_OBJECTPROFILENODE_ARRAY;
	}

	final ILink m_link;
	final Object m_obj;
	int m_refcount;
	AbstractShellProfileNode m_shell;
	IObjectProfileNode[] m_children;
	// private: ...............................................................
} // end of class
// ----------------------------------------------------------------------------
